{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "76460724",
   "metadata": {
    "cell_id": 1
   },
   "source": [
    "# This demo illustrates the functionality of Research API Python Wrapper"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5b7a686",
   "metadata": {
    "cell_id": 115
   },
   "source": [
    "## Getting Started\n",
    "\n",
    "Below we provide the examples of the queries using the Wrapper, illustrate its functionality, as well as provide some examples of the types of analysis possible with TikTok Research API\n",
    "\n",
    "The information on TikTok Research API can be found here: https://developers.tiktok.com/doc/research-api-codebookhttps://developers.tiktok.com/doc/research-api-codebook"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32bc3b65",
   "metadata": {
    "cell_id": 80
   },
   "source": [
    "### Let's install the package"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42a8ef51",
   "metadata": {
    "cell_id": 81
   },
   "outputs": [],
   "source": [
    "pip install TikTokResearchApi"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75242b88",
   "metadata": {
    "cell_id": 82
   },
   "source": [
    "### Loading the Wrapper and other packages you might potentially need"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf0aa036",
   "metadata": {
    "cell_id": 16
   },
   "outputs": [],
   "source": [
    "from tiktok_research_api import *\n",
    "\n",
    "import pandas as pd \n",
    "\n",
    "import nltk\n",
    "from nltk.tokenize import word_tokenize\n",
    "from nltk.probability import FreqDist\n",
    "from nltk.corpus import stopwords\n",
    "\n",
    "from datetime import datetime\n",
    "from datetime import timedelta\n",
    "\n",
    "from wordcloud import WordCloud\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "685d93ce",
   "metadata": {
    "cell_id": 79
   },
   "source": [
    " First thing first, you need to initialize the API client. For that you will need you client_key and client_secret that you will see in your TikTok for Developers portal  https://developers.tiktok.com/research after your application has been approved"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d370f060",
   "metadata": {
    "cell_id": 78
   },
   "outputs": [],
   "source": [
    "# Initialize the API client\n",
    "qps = 5 #rate limiter\n",
    "client_key = 'your_client_key'\n",
    "client_secret = 'your_client_secret'\n",
    "research_api = TikTokResearchAPI(client_key, client_secret, qps)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78114564",
   "metadata": {
    "cell_id": 116
   },
   "source": [
    "## Querying "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9dbbc8a",
   "metadata": {
    "cell_id": 114
   },
   "source": [
    "Currently, the Research API Wrapper supports following endpoints:\n",
    "\n",
    "- Videos endpoint\n",
    "\n",
    "- Users endpoint\n",
    "\n",
    "- Comments endpoint\n",
    "\n",
    "- User Pinned Videos endpoint\n",
    "\n",
    "- User Liked Videos endpoint\n",
    "\n",
    "- User Reposted Videos endpoint\n",
    "\n",
    "- User Following endpoint\n",
    "\n",
    "- User Followers endpoint\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "decd2d17",
   "metadata": {
    "cell_id": 117
   },
   "source": [
    "### Pagination\n",
    "\n",
    "If you want to retrieve more than 100 videos (max_count of videos per response), you need search_id and cursor. \n",
    "\n",
    "Search_id - unique identifier assigned to a cached search result. This identifier enables the resumption of a prior search and retrieval of additional results based on the same search criteria. The unique identifier assigned to a cached search result. \n",
    "\n",
    "Cursor - index assigned to a video, allowing you to continue your query where you left off.\n",
    "\n",
    "\n",
    "The wrapper faciltates the pagination, through following arguments:\n",
    "\n",
    "'fetch_all_pages\" (default is False) argument. When set to True, handles pagination automatically. If False, it returns only the initial API response.\n",
    "\n",
    "'max_total' (default is 100000) argument. If you want to return more than max_count, but limit for how much is returned.\n",
    "\n",
    "For Video Endpoint, the Wrapper allows to query for a period for more than 30 days, but continuing the search would require start_date and end_date (returned in response)\n",
    "\n",
    "For the endpoints listed below, enabling the \"fetch_all_pages\" argument allows automatic pagination. When enabled, the function handles pagination automatically. If disabled (set to false) or left unset, it returns only the initial API response.\n",
    "\n",
    "| R Wrapper Function      | API Endpoint |\n",
    "| ----------- | ----------- |\n",
    "| query_videos      | /v2/research/video/query/|\n",
    "| query_user_followers   | /v2/research/user/followers/|\n",
    "| query_user_following   | /v2/research/user/following/|\n",
    "| query_user_liked_videos   | /v2/research/user/liked_videos/|\n",
    "| query_video_comments   | /v2/research/video/comment/list/|\n",
    "| query_user_reposted_videos   | /v2/research/user/reposted_videos/|\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a210616",
   "metadata": {
    "cell_id": 2
   },
   "source": [
    "### To query Videos endpoint"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c6c359a",
   "metadata": {
    "cell_id": 9
   },
   "source": [
    "If you decide to query the video endpoint, the possible options are below.\n",
    "Can search using one of:\n",
    "\n",
    "\"create_date\": when the video was created\n",
    "\n",
    "\"username\": the handle/username of the creator\n",
    "\n",
    "\"region_code\": the region where the video was uploaded\n",
    "\n",
    "\"video_id\": the unique ID of the video\n",
    "\n",
    "\"hashtag_name\": indexed hashtag\n",
    "\n",
    "\"keyword\": a string in the video description (can be a hashtag or something else)\n",
    "\n",
    "\"music_id\": the unique ID of the audio\n",
    "\n",
    "\"effect_id\": the unique ID of the effects used\n",
    "\n",
    "\"video_length\": the length of the video in seconds\n",
    "\n",
    "OPERATIONS:\n",
    "\n",
    "\"EQ\" = equal to\n",
    "\n",
    "\"IN\" = in a list\n",
    "\n",
    "\"GT\" = greater than\n",
    "\n",
    "\"GTE\" = greater than or equal to\n",
    "\n",
    "\"LT\" = less than\n",
    "\n",
    "\"LTE\" = less than or equal to\n",
    "\n",
    "All search values should be input as a list of strings. E.g., region_code: ['US','CA']\n",
    "\n",
    "All possible regions: 'FR', 'TH', 'MM', 'BD', 'IT', 'NP', 'IQ', 'BR', 'US', 'KW', 'VN', 'AR', 'KZ', 'GB', 'UA', 'TR', 'ID', 'PK', 'NG', 'KH', 'PH', 'EG', 'QA', 'MY', 'ES', 'JO', 'MA', 'SA', 'TW', 'AF', 'EC', 'MX', 'BW', 'JP', 'LT', 'TN', 'RO', 'LY', 'IL', 'DZ', 'CG', 'GH', 'DE', 'BJ', 'SN', 'SK', 'BY', 'NL', 'LA', 'BE', 'DO', 'TZ', 'LK', 'NI', 'LB', 'IE', 'RS', 'HU', 'PT', 'GP', 'CM', 'HN', 'FI', 'GA', 'BN', 'SG', 'BO', 'GM', 'BG', 'SD', 'TT', 'OM', 'FO', 'MZ', 'ML', 'UG', 'RE', 'PY', 'GT', 'CI', 'SR', 'AO', 'AZ', 'LR', 'CD', 'HR', 'SV', 'MV', 'GY', 'BH', 'TG', 'SL', 'MK', 'KE', 'MT', 'MG', 'MR', 'PA', 'IS', 'LU', 'HT', 'TM', 'ZM', 'CR', 'NO', 'AL', 'ET', 'GW', 'AU', 'KR', 'UY', 'JM', 'DK', 'AE', 'MD', 'SE', 'MU', 'SO', 'CO', 'AT', 'GR', 'UZ', 'CL', 'GE', 'PL', 'CA', 'CZ', 'ZA', 'AI', 'VE', 'KG', 'PE', 'CH', 'LV', 'PR', 'NZ', 'TL', 'BT', 'MN', 'FJ', 'SZ', 'VU', 'BF', 'TJ', 'BA', 'AM', 'TD', 'SI', 'CY', 'MW', 'EE', 'XK', 'ME', 'KY', 'YE', 'LS', 'ZW', 'MC', 'GN', 'BS', 'PF', 'NA', 'VI', 'BB', 'BZ', 'CW', 'PS', 'FM', 'PG', 'BI', 'AD', 'TV', 'GL', 'KM', 'AW', 'TC', 'CV', 'MO', 'VC', 'NE', 'WS', 'MP', 'DJ', 'RW', 'AG', 'GI', 'GQ', 'AS', 'AX', 'TO', 'KN', 'LC', 'NC', 'LI', 'SS', 'IR', 'SY', 'IM', 'SC', 'VG', 'SB', 'DM', 'KI', 'UM', 'SX', 'GD', 'MH', 'BQ', 'YT', 'ST', 'CF', 'BM', 'SM', 'PW', 'GU', 'HK', 'IN', 'CK', 'AQ', 'WF', 'JE', 'MQ', 'CN', 'GF', 'MS', 'GG', 'TK', 'FK', 'PM', 'NU', 'MF', 'ER', 'NF', 'VA', 'IO', 'SH', 'BL', 'CU', 'NR', 'TP', 'BV', 'EH', 'PN', 'TF', 'RU'\n",
    "\n",
    "API Documention: https://developers.tiktok.com/doc/research-api-specs-query-videos/\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18795751",
   "metadata": {
    "cell_id": 85
   },
   "outputs": [],
   "source": [
    "# Define query object\n",
    "query_criteria_1 = Criteria(\n",
    "    operation=\"EQ\", field_name=\"hashtag_name\", field_values=[\"hashtag\"]\n",
    ")\n",
    "query_criteria_2 = Criteria(\n",
    "    operation=\"IN\", field_name=\"region_code\", field_values=[\"region\"]\n",
    ")\n",
    "\n",
    "# You can define criteria using:\n",
    "#'and_criteria' specify that all the conditions in the list must be met\n",
    "#'or_criteria' specify that at least one of the conditions in the list must be met\n",
    "#'not_criteria' specify that none of the conditions in the list must be met\n",
    "query = Query(and_criteria=[query_criteria_1, query_criteria_2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "02505cd6",
   "metadata": {
    "cell_id": 83
   },
   "outputs": [],
   "source": [
    "video_fields = \"id,create_time,username,region_code,video_description,video_duration,hashtag_names,view_count,like_count,comment_count,share_count\"\n",
    "video_columns = video_fields.split(',')\n",
    "video_request = QueryVideoRequest(\n",
    "    fields=video_fields,    \n",
    "    query = query,\n",
    "    start_date=\"20240101\",\n",
    "    end_date=\"20240201\",\n",
    "    max_count=100,\n",
    "    max_total = 1000\n",
    ")\n",
    "\n",
    "videos, search_id, cursor, has_more, start_date, end_date = research_api.query_videos(video_request, fetch_all_pages=True)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ef2803e",
   "metadata": {
    "cell_id": 118
   },
   "source": [
    "If you want to continue your search, you can specify your search_id, cursor, and start_date, and end_date in your next query. Please make sure to use search_id provided at the end of the query."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "21c6a9a6",
   "metadata": {
    "cell_id": 119
   },
   "outputs": [],
   "source": [
    "video_request = QueryVideoRequest(\n",
    "    fields=video_fields,    \n",
    "    query = query,\n",
    "    start_date=start_date,\n",
    "    end_date=end_date,\n",
    "    max_count=100,\n",
    "    max_total = 1000,\n",
    "    search_id = search_id,\n",
    "    cursor = cursor\n",
    "\n",
    ")\n",
    "\n",
    "videos, search_id, cursor, has_more, start_date, end_date = research_api.query_videos(video_request, fetch_all_pages=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "84c7a301",
   "metadata": {
    "cell_id": 89
   },
   "outputs": [],
   "source": [
    "video_df = pd.DataFrame(videos, columns = video_columns)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49b4aa52",
   "metadata": {
    "cell_id": 93
   },
   "outputs": [],
   "source": [
    "#you might want to format the variables\n",
    "column_types = {'id': 'str', 'create_time': 'int', 'username': 'str', 'region_code': 'str', 'video_description': 'str', 'voice_to_text': 'str', 'hashtag_names': 'object', 'view_count': 'int', 'like_count': 'int', 'comment_count': 'int', 'share_count': 'int', 'music_id': 'str', 'effect_ids': 'str', 'playlist_id': 'str'}\n",
    "int_columns = ['view_count','like_count','comment_count','share_count']\n",
    "\n",
    "video_df['music_id'] = video_df['music_id'].apply(lambda x: '{:.0f}'.format(x))\n",
    "video_df['playlist_id'] = video_df['playlist_id'].apply(lambda x: '{:.0f}'.format(x) if not pd.isna(x) else '')\n",
    "video_df[int_columns] = video_df[int_columns].fillna(0)\n",
    "video_df = video_df.fillna('')\n",
    "video_df = video_df.astype(column_types)\n",
    "\n",
    "# convert create_time to a human-readable datetime\n",
    "video_df['datetime'] = pd.to_datetime(video_df['create_time'], unit='s').dt.strftime('%Y-%m-%d %H:%M:%S')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb4a7a13",
   "metadata": {
    "cell_id": 91
   },
   "source": [
    "#### From here, for example, you can:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96728d4e",
   "metadata": {
    "cell_id": 108
   },
   "source": [
    "#### Select specific rows to investigate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9706ddca",
   "metadata": {
    "cell_id": 92
   },
   "outputs": [],
   "source": [
    "pd.set_option('display.max_colwidth', 300) # use None for no boundaries\n",
    "\n",
    "video_df[\n",
    "    #(video_df['video_description'].str.contains('word', case=False, na=False)) #if you want to filter by a specific word\n",
    "    (video_df['view_count'] > 1000) #if you want to filter by number of views\n",
    "    #|(video_df['effect_ids'].apply(lambda x: '12345' in x)) #if you want to filter by effect_id, etc\n",
    "    ]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15517952",
   "metadata": {
    "cell_id": 96
   },
   "source": [
    "#### Generate the TikTok link so you can view the video\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a8efc6f",
   "metadata": {
    "cell_id": 94
   },
   "outputs": [],
   "source": [
    "#To get the video link for a specific video_id, you will need a username and the video_id:\n",
    "def get_video_link(df, video_id):\n",
    "    username_row = df[df['id'] == video_id]\n",
    "    if not username_row.empty:\n",
    "        username =username_row['username'].values[0]\n",
    "        print(f\"https://www.tiktok.com/@{username}/video/{video_id}\")\n",
    "    else:\n",
    "        print(f\"No user found with video {video_id}\")\n",
    "\n",
    "get_video_link(video_df, 'video_id')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e63d36ce",
   "metadata": {
    "cell_id": 95
   },
   "source": [
    "#### Look at the descriptive statistics of the dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a7d063c",
   "metadata": {
    "cell_id": 97
   },
   "outputs": [],
   "source": [
    "def describe(df, stats):\n",
    "    d = df.describe()\n",
    "    return pd.concat([d, df.reindex(d.columns, axis = 1).agg(stats)])\n",
    "pd.options.display.float_format = '{:.2f}'.format\n",
    "describe(video_df[['view_count','like_count','comment_count','share_count']], ['sum', 'skew', 'kurt'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e85b962",
   "metadata": {
    "cell_id": 98
   },
   "source": [
    "#### Get the most frequent words in the description"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a22bac9f",
   "metadata": {
    "cell_id": 99
   },
   "outputs": [],
   "source": [
    "def get_most_frequent_words(df, text_column_name, num_words=10):\n",
    "    \"\"\"\n",
    "    Get the most frequent words from a text column in a DataFrame.\n",
    "    \n",
    "    Parameters:\n",
    "    - df: DataFrame\n",
    "        The DataFrame containing the text data.\n",
    "    - text_column_name: str\n",
    "        The name of the text column in the DataFrame.\n",
    "    - num_words: int\n",
    "        The number of top words to retrieve (default is 10).\n",
    "\n",
    "    Returns:\n",
    "    - list of tuples\n",
    "        A list of (word, frequency) tuples for the most frequent words.\n",
    "    \"\"\"\n",
    "    # Combine all the text in the specified column into a single string\n",
    "    all_text = ' '.join(df[text_column_name])\n",
    "\n",
    "    # Tokenize the text into words\n",
    "    words = word_tokenize(all_text)\n",
    "\n",
    "    # Remove stopwords (common words like 'the', 'and', 'in', etc.)\n",
    "    stop_words = set(stopwords.words('english'))\n",
    "    stop_words.update(['fyp','tiktok','foryou','foryoupage','viral','follow']) # add more stopwords if needed\n",
    "    filtered_words = [word.lower() for word in words if word.lower() not in stop_words and word.isalpha()]\n",
    "\n",
    "    # Calculate word frequencies\n",
    "    fdist = FreqDist(filtered_words)\n",
    "\n",
    "    # Get the most frequent words\n",
    "    most_common_words = fdist.most_common(num_words)\n",
    "\n",
    "    return most_common_words\n",
    "\n",
    "top_words_description = get_most_frequent_words(video_df, 'video_description', num_words=20)\n",
    "print(top_words_description)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79d19fa9",
   "metadata": {
    "cell_id": 5
   },
   "source": [
    "### Query Users endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4031e63b",
   "metadata": {
    "cell_id": 11
   },
   "outputs": [],
   "source": [
    "username = \"username\"\n",
    "user_info_request = QueryUserInfoRequest(\n",
    "    username= username\n",
    ")\n",
    "userinfo = research_api.query_user_info(user_info_request)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6699011f",
   "metadata": {
    "cell_id": 42
   },
   "outputs": [],
   "source": [
    "user_df = pd.DataFrame(userinfo,index=[0])\n",
    "user_df "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "701093ce",
   "metadata": {
    "cell_id": 112
   },
   "source": [
    "### Retrieving information for multiple accounts:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9ef4d7aa",
   "metadata": {
    "cell_id": 110
   },
   "outputs": [],
   "source": [
    "# For example, if you want to get query the users, who created videos with more than 100000 views, you can do the following:\n",
    "selected_df = video_df[video_df['view_count'] > 100000] #filter the video\n",
    "print(f\"New video count: {len(selected_df)}\")\n",
    "usernames = selected_df['username'].unique() # get the list of users\n",
    "print(f\"Unique creator count: {len(usernames)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f54b23e2",
   "metadata": {
    "cell_id": 111
   },
   "outputs": [],
   "source": [
    "# Create an empty DataFrame to store the user information\n",
    "accounts_df = pd.DataFrame()\n",
    "# Loop through the usernames and query the user information\n",
    "for username in usernames:\n",
    "    user_info_request = QueryUserInfoRequest(\n",
    "        username= username\n",
    "    )\n",
    "    userinfo = research_api.query_user_info(user_info_request)\n",
    "    user_df = pd.DataFrame(userinfo,index=[0])\n",
    "    accounts_df = pd.concat([accounts_df, user_df])\n",
    "\n",
    "accounts_df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f40e444f",
   "metadata": {
    "cell_id": 17
   },
   "source": [
    "### Query Comments "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90c1e79c",
   "metadata": {
    "cell_id": 19
   },
   "outputs": [],
   "source": [
    "video_id=\"video_id\"\n",
    "video_comment_request = QueryVideoCommentsRequest(\n",
    "    video_id=video_id,        \n",
    "    max_count=100,\n",
    ")\n",
    "comments, cursor, has_more = research_api.query_video_comments(video_comment_request, fetch_all_pages=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a8040720",
   "metadata": {
    "cell_id": 41
   },
   "outputs": [],
   "source": [
    "video_comments = pd.DataFrame(comments)\n",
    "video_comments"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e56c8c2a",
   "metadata": {
    "cell_id": 109
   },
   "source": [
    "#### For instance, you might want to visualize the content of the comments through a wordcloud:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9cdf408d",
   "metadata": {
    "cell_id": 102
   },
   "outputs": [],
   "source": [
    "def create_wordcloud_from_column(df, column_name):\n",
    "    \"\"\"\n",
    "    Create a word cloud from a column of text in a DataFrame.\n",
    "\n",
    "    Parameters:\n",
    "    - df: DataFrame\n",
    "        The DataFrame containing the data.\n",
    "    - column_name: str\n",
    "        The name of the column with text data.\n",
    "\n",
    "    Returns:\n",
    "    - None\n",
    "        Displays the word cloud plot.\n",
    "    \"\"\"\n",
    "    # Combine all the text in the specified column into a single string\n",
    "    all_text = ' '.join(df[column_name])\n",
    "\n",
    "    # Create a WordCloud object\n",
    "    wordcloud = WordCloud(width=800, height=400, background_color='white').generate(all_text)\n",
    "\n",
    "    # Display the word cloud using matplotlib\n",
    "    plt.figure(figsize=(10, 5))\n",
    "    plt.imshow(wordcloud, interpolation='bilinear')\n",
    "    plt.axis('off')\n",
    "    #plt.title(f'Word Cloud from {column_name}')\n",
    "    plt.show()\n",
    "\n",
    "create_wordcloud_from_column(video_comments, 'text')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e7a2e24",
   "metadata": {
    "cell_id": 25
   },
   "source": [
    "### Query User Pinned Videos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c944d621",
   "metadata": {
    "cell_id": 20
   },
   "outputs": [],
   "source": [
    "username = \"username\"\n",
    "user_pinned_videos_request = QueryUserPinnedVideosRequest(\n",
    "    username= username\n",
    ")\n",
    "pinned_videos = research_api.query_user_pinned_videos(user_pinned_videos_request)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29330700",
   "metadata": {
    "cell_id": 35
   },
   "outputs": [],
   "source": [
    "pd.DataFrame.from_dict(pinned_videos)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1947286f",
   "metadata": {
    "cell_id": 27
   },
   "source": [
    "### Query User Liked Videos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae71c979",
   "metadata": {
    "cell_id": 50
   },
   "outputs": [],
   "source": [
    "username = \"username\"\n",
    "user_liked_videos = QueryUserLikedVideosRequest(\n",
    "    username= username\n",
    ")\n",
    "liked_videos, cursor, has_more = research_api.query_user_liked_videos(user_liked_videos)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8cba9ff4",
   "metadata": {
    "cell_id": 53
   },
   "outputs": [],
   "source": [
    "liked_videos_df = pd.DataFrame(liked_videos)\n",
    "liked_videos_df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ceb9cf4e",
   "metadata": {
    "cell_id": 29
   },
   "source": [
    "### Query Reposted Videos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29408281",
   "metadata": {
    "cell_id": 23
   },
   "outputs": [],
   "source": [
    "username=\"username\"\n",
    "reposted_videos_request = QueryUserRepostedVideosRequest(\n",
    "    username=username                                                \n",
    ")\n",
    "reposted_videos, cursor, has_more  = research_api.query_user_reposted_videos(reposted_videos_request)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3112907d",
   "metadata": {
    "cell_id": 37
   },
   "outputs": [],
   "source": [
    "reposted_videos = pd.DataFrame(reposted_videos)\n",
    "reposted_videos"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b36ef02c",
   "metadata": {
    "cell_id": 31
   },
   "source": [
    "### Query User Following"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24bd4c9c",
   "metadata": {
    "cell_id": 22
   },
   "outputs": [],
   "source": [
    "username = \"username\"\n",
    "user_following_request = QueryUserFollowingRequest(\n",
    "    username= username\n",
    ")\n",
    "user_following, cursor, has_more = research_api.query_user_following(user_following_request, fetch_all_pages=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a97d1fb1",
   "metadata": {
    "cell_id": 38
   },
   "outputs": [],
   "source": [
    "following = pd.DataFrame(user_following)\n",
    "following"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "174a7b4f",
   "metadata": {
    "cell_id": 33
   },
   "source": [
    "### Query User Followers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f39fdd06",
   "metadata": {
    "cell_id": 24
   },
   "outputs": [],
   "source": [
    "username = \"username\"\n",
    "user_followers_request = QueryUserFollowersRequest(\n",
    "    username= username\n",
    ")\n",
    "user_followers = research_api.query_user_followers(user_followers_request, fetch_all_pages=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4b40a9f",
   "metadata": {
    "cell_id": 39
   },
   "outputs": [],
   "source": [
    "followers = pd.DataFrame(user_followers)\n",
    "followers"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  },
  "max_cell_id": 124
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
